package com.freewater.springboot.demo.aop.pointcuts;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.util.ClassUtils;

/**
 * target
 * 格式说明
 * target(类型全限定名)：判断目标对象的类型是否和指定的类型匹配；表达式必须是类型全限定名，不支持通配符。
 * target(x)匹配规则：x.getClass().isAssignableFrom(target.getClass());
 * <p>
 * 链接：<a href="https://juejin.cn/post/7077425331954515999">Spring系列25：Spring AOP 切点详解</a>
 */
@Aspect
public class PointcutTarget {
    interface I1 {
        void m();
    }

    static class C1 implements I1 {

        @Override
        public void m() {
            System.out.println("C1 m()");
        }
    }

    // 这里的target指的是被代理的目标对象（例子为C1的实例），限制target对象是C1类型或是其子类
    @Pointcut("target(com.freewater.springboot.demo.aop.pointcuts.PointcutTarget.C1)")
    public void pc() {
    }

    @Before("pc()")
    public void before(JoinPoint joinPoint) {
        System.out.println("before: " + joinPoint);
    }

    public static void main(String[] args) {
        I1 target = new C1();
        AspectJProxyFactory proxyFactory = new AspectJProxyFactory();
        proxyFactory.setTarget(target);
        // 获取C1上所有接口 spring工具类提供的方法
        Class<?>[] allInterfaces = ClassUtils.getAllInterfaces(target);
        // 设置代理接口
        proxyFactory.setInterfaces(allInterfaces);
        // 添加切面
        proxyFactory.addAspect(PointcutTarget.class);
        // 获取代理
        I1 proxy = proxyFactory.getProxy();
        // 调用方法
        proxy.m();
        System.out.println("JDK代理? " + AopUtils.isJdkDynamicProxy(proxy));
        System.out.println("CGLIB代理? " + AopUtils.isCglibProxy(proxy));
        // 判断代理对象是否是I1类型的
        System.out.println(I1.class.isAssignableFrom(proxy.getClass()));
        //判断代理对象是否是C1类型的
        System.out.println(C1.class.isAssignableFrom(proxy.getClass()));
    }
}
